//
//  AudioTableCell.swift
//  GhostWorld
//
//  Created by Kam on 2018/4/30.
//  Copyright © 2018 LKGood. All rights reserved.
//

import UIKit

class AudioTableCell: UITableViewCell {

  enum AudioTableCellMode {
    case normal, selectable
  }
  
  private enum DownloadMode {
    case notDownloaded, inQueue, downloaded
  }
  
  // MARK: - IBOutlets
  
  @IBOutlet private weak var containerView: UIView!
  @IBOutlet private weak var nameLabel: UILabel!
  @IBOutlet private weak var nowPlayingView: UIView!
  @IBOutlet private weak var playProgressView: AudioTableCellPlayProgressView!
  @IBOutlet private weak var containerLeadingConstraint: NSLayoutConstraint!
  @IBOutlet private weak var rightView: UIView!
  @IBOutlet private weak var rightViewWidthConstraint: NSLayoutConstraint!
  @IBOutlet private weak var selectionImageView: UIImageView!
  @IBOutlet private weak var downloadButton: UIButton!
  @IBOutlet private weak var downloadProgressView: AudioTableCellDownloadProgressView!
  @IBOutlet private weak var downloadPauseButton: UIButton!
  
  // MARK: - Private vars
  
  private let selectView = UIView()
  private var audio: Audio?
  
  private var downloadMode: DownloadMode = .notDownloaded {
    didSet {
      UIView.animate(withDuration: 0.2, animations: {
        self.rightView.alpha = 0
      }) { _ in
        switch self.downloadMode {
        case .notDownloaded:
          self.downloadButton.alpha = 1
          self.downloadProgressView.alpha = 0
          self.downloadPauseButton.alpha = 0
        case .inQueue:
          self.downloadButton.alpha = 0
          self.downloadProgressView.alpha = 1
          self.downloadPauseButton.alpha = 1
        case .downloaded:
          self.downloadButton.alpha = 0
          self.downloadProgressView.alpha = 0
          self.downloadPauseButton.alpha = 0
        }
        UIView.animate(withDuration: 0.2, animations: {
          self.rightView.alpha = 1
        })
      }
    }
  }
  
  // MARK: - Private methods
  
  private func addNotifications() {
    // playing
    NotificationCenter.default.addObserver(self, selector: #selector(changeNowPlayingHandler), name: .changeNowPlaying, object: nil)
    NotificationCenter.default.addObserver(self, selector: #selector(updateNowPlayingProgressHandler), name: .updateNowPlayingProgress, object: nil)
    
    // downloading
    NotificationCenter.default.addObserver(self, selector: #selector(updateDownloadProgress(notifiation:)), name: .downloadDidUpdateProgress, object: nil)
    NotificationCenter.default.addObserver(self, selector: #selector(downloadFinished(notifiation:)), name: .downloadFinished, object: nil)
    NotificationCenter.default.addObserver(self, selector: #selector(downloadDidPaused(notifiation:)), name: .downloadDidPaused, object: nil)
    NotificationCenter.default.addObserver(self, selector: #selector(downloadDidResumed(notifiation:)), name: .downloadDidResumed, object: nil)
    NotificationCenter.default.addObserver(self, selector: #selector(downloadDidFailed(notifiation:)), name: .downloadFailded, object: nil)
    
    // streaming caching
    NotificationCenter.default.addObserver(self, selector: #selector(streamingCacheFinished), name: .streamingCacheFinished, object: nil)
  }
  
  @objc private func changeNowPlayingHandler() {
    isAudioNowPlaying = (NowPlayingManager.shared.audio?.id == audio?.id)
  }
  
  @objc private func updateNowPlayingProgressHandler() {
    if NowPlayingManager.shared.audio?.id == audio?.id,
      let audio = self.audio {
      playProgressView.progress = audio.getPlayProgress()
    }
  }
  
  @objc private func updateDownloadProgress(notifiation: Notification) {
    if let object = notifiation.userInfo?[DownloadNotificationObject.key] as? DownloadNotificationObject {
      if object.downloadModel.fileURL == audio?.url {
        
        if downloadMode != .inQueue {
          downloadMode = .inQueue
        }
        downloadProgressView.progress = object.downloadModel.progress
      }
    }
  }
  
  @objc private func downloadFinished(notifiation: Notification) {
    if let object = notifiation.userInfo?[DownloadNotificationObject.key] as? DownloadNotificationObject {
      if object.downloadModel.fileURL == audio?.url {
        downloadMode = .downloaded
      }
    }
  }
  
  @objc private func downloadDidPaused(notifiation: Notification) {
    if let object = notifiation.userInfo?[DownloadNotificationObject.key] as? DownloadNotificationObject {
      if object.downloadModel.fileURL == audio?.url {
        downloadMode = .notDownloaded
      }
    }
  }
  
  @objc private func downloadDidResumed(notifiation: Notification) {
    if let object = notifiation.userInfo?[DownloadNotificationObject.key] as? DownloadNotificationObject {
      if object.downloadModel.fileURL == audio?.url {
        downloadMode = .inQueue
      }
    }
  }
  
  @objc private func downloadDidFailed(notifiation: Notification) {
    if let object = notifiation.userInfo?[DownloadNotificationObject.key] as? DownloadNotificationObject {
      if object.downloadModel.fileURL == audio?.url {
        downloadMode = .notDownloaded
      }
    }
  }
  
  @objc private func streamingCacheFinished(notifiation: Notification) {
    if let currentPlayingAudio = NowPlayingManager.shared.audio {
      if currentPlayingAudio.url == audio?.url {
        downloadMode = .downloaded
      }
    }
  }
  
  // MARK: - Public vars
  
  var isAudioNowPlaying = false {
    didSet {
      UIView.animate(withDuration: 0.3) {
        self.nowPlayingView.alpha = (self.isAudioNowPlaying ? 1 : 0)
      }
    }
  }
  
  var isChecked: Bool = false {
    didSet {
      selectionImageView.image = UIImage(named: (isChecked ? "AudioCellSelectedIcon" : "AudioCellUnSelectedIcon"))
    }
  }
  
  var isButtonsEnabled: Bool = true {
    didSet {
      downloadButton.isUserInteractionEnabled = isButtonsEnabled
      downloadPauseButton.isUserInteractionEnabled = isButtonsEnabled
    }
  }
  
  // MARK: - Lifecycle
  
  override func awakeFromNib() {
    super.awakeFromNib()
    addNotifications()
    
    contentView.backgroundColor = .clear
    
    containerView.layer.cornerRadius = 4
    containerView.clipsToBounds = true
    
    nowPlayingView.alpha = 0
    
    // selected background view
    let backgroundView = UIView()
    backgroundView.backgroundColor = .clear
    
    selectView.backgroundColor = UIColor(fromRGB: 0x98000C)
    selectView.clipsToBounds = true
    selectView.layer.cornerRadius = 4
    backgroundView.addSubview(selectView)
    selectedBackgroundView = backgroundView
  }
  
  override func layoutSubviews() {
    super.layoutSubviews()
    
    selectView.frame = containerView.frame
  }
  
  override func prepareForReuse() {
    super.prepareForReuse()
    
    nameLabel.text = "--"
    nowPlayingView.alpha = 0
    
    playProgressView.progress = 0
    downloadProgressView.progress = 0
    rightView.isHidden = true
  }
  
  deinit {
    NotificationCenter.default.removeObserver(self)
  }
  
  // MARK: - IBActions
  
  @IBAction func addToDownloadQueue() {
    if let audio = self.audio {
      AudioDownloadManager.shared.add(audio: audio)
      downloadMode = .inQueue
    }
  }
  
  @IBAction func pauseDownload() {
    if let audio = self.audio {
      AudioDownloadManager.shared.pause(audio: audio)
    }
  }
  
  // MARK: - Public methods
  
  func prepare(audio: Audio, mode: AudioTableCellMode = .normal) {
    self.audio = audio
    nameLabel.text = "\(audio.name ?? "--")"
    
    // check is playing
    if let nowPlayingAudio = NowPlayingManager.shared.audio,
      audio.id == nowPlayingAudio.id {
      nowPlayingView.alpha = 1
    } else {
      nowPlayingView.alpha = 0
    }
    
    // mode
    switch mode {
    case .normal:
      selectionImageView.isHidden = true
      containerLeadingConstraint.constant = 16
      rightView.isHidden = false
      rightView.alpha = 0
      rightViewWidthConstraint.constant = 44
      
      // download mode
      if audio.localURL != nil {
        downloadMode = .downloaded
      } else {
        if AudioDownloadManager.shared.audioIsInQueue(audio) {
          downloadMode = .inQueue
        } else {
          downloadMode = .notDownloaded
        }
      }
      rightView.isHidden = (audio.localURL != nil)
      downloadProgressView.progress = 0
      
    case .selectable:
      selectionImageView.isHidden = false
      containerLeadingConstraint.constant = 40
      rightView.isHidden = true
      rightViewWidthConstraint.constant = 0
    }
    
    // set play progress
    playProgressView.progress = audio.getPlayProgress()
  }
}

extension AudioTableCell {
  static let defaultHeight: CGFloat = 60
}
